package com.atguigu.gmall.cart.service;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.cart.entity.Cart;
import com.atguigu.gmall.cart.feign.GmallPmsClient;
import com.atguigu.gmall.cart.feign.GmallSmsClient;
import com.atguigu.gmall.cart.feign.GmallWmsClient;
import com.atguigu.gmall.cart.interceptor.LoginInterceptor;
import com.atguigu.gmall.common.bean.ResponseVo;
import com.atguigu.gmall.common.bean.UserInfo;
import com.atguigu.gmall.common.exception.CartException;
import com.atguigu.gmall.pms.entity.SkuAttrValueEntity;
import com.atguigu.gmall.pms.entity.SkuEntity;
import com.atguigu.gmall.sms.inter.vo.ItemSaleVo;
import com.atguigu.gmall.wms.entity.WareSkuEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.concurrent.ListenableFuture;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CartService {

    @Autowired
    private GmallPmsClient pmsClient;
    @Autowired
    private GmallSmsClient smsClient;
    @Autowired
    private GmallWmsClient wmsClient;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private CartAsyncService cartAsyncService;

    private static final String KEY_PREFIX = "cart:info:";
    private static final String PRICE_PREFIX = "cart:price:";

    public void addCart(Cart cart) {
        // 1.获取登录信息
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        String userId = userInfo.getUserKey();
        if (userInfo.getUserId() != null) {
            userId = userInfo.getUserId().toString();
        }

        // 2.获取redis中该用户的购物车,内层Map
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);

        // 3.判断该用户的购物车信息是否已包含了该商品
        String skuId = cart.getSkuId().toString();
        BigDecimal count = cart.getCount(); // 要新增的数量
        if (hashOps.hasKey(skuId)) {
            // 4.包含 更新数量
            String cartJson = hashOps.get(skuId).toString(); // 已有的购物车
            cart = JSON.parseObject(cartJson, Cart.class);
            cart.setCount(cart.getCount().add(count));
            // 更新后的购物车内容写入数据库redis，mysql

            this.cartAsyncService.updateCartByUserIdAndSkuId(userId,cart);
        } else {
            // 5.不包含 给用户新增购物车记录 skuId count
            cart.setUserId(userId);
            cart.setCheck(true); // 商品刚加入购物车时，默认为选中状态
            // 根据skuId查询sku
            ResponseVo<SkuEntity> skuEntityResponseVo = this.pmsClient.querySkuById(cart.getSkuId());
            SkuEntity skuEntity = skuEntityResponseVo.getData();
            if (skuEntity != null) {
                cart.setTitle(skuEntity.getTitle());
                cart.setPrice(skuEntity.getPrice());
                cart.setDefaultImage(skuEntity.getDefaultImage());
            } else {
                throw new CartException("您加入的商品不存在");
            }
            // 根据skuId查询销售属性
            ResponseVo<List<SkuAttrValueEntity>> listResponseVo = this.pmsClient.querySkuAttrValueBySkuId(cart.getSkuId());
            List<SkuAttrValueEntity> skuAttrValueEntities = listResponseVo.getData();
            cart.setSaleAttrs(JSON.toJSONString(skuAttrValueEntities));
            // 根据skuId查询营销信息
            ResponseVo<List<ItemSaleVo>> itemSaleVoResponseVo = this.smsClient.querySalesBySkuId(cart.getSkuId());
            List<ItemSaleVo> itemSaleVos = itemSaleVoResponseVo.getData();
            cart.setSales(JSON.toJSONString(itemSaleVos));
            // 根据skuId查询库存信息
            ResponseVo<List<WareSkuEntity>> listResponseVo1 = this.wmsClient.queryWaresBySkuId(cart.getSkuId());
            List<WareSkuEntity> wareSkuEntities = listResponseVo1.getData();
            if (!CollectionUtils.isEmpty(wareSkuEntities)) {
                cart.setStore(wareSkuEntities.stream().anyMatch(wareSkuEntity -> wareSkuEntity.getStock() - wareSkuEntity.getStockLocked() > 0));
            }

            this.cartAsyncService.saveCart(userId,cart);
            // 缓存实时价格
            this.redisTemplate.opsForValue().set(PRICE_PREFIX+skuId,skuEntity.getPrice().toString());
        }
        hashOps.put(skuId, JSON.toJSONString(cart));
    }

    public Cart queryCartBySkuId(Cart cart) {
        // 1.获取登录信息
        String userId = getUserId();
        String key = KEY_PREFIX + userId;
        Long skuId = cart.getSkuId();
        // 2.获取redis中该用户的购物车
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(key);
        if (hashOps.hasKey(skuId.toString())) {
            String cartJson = hashOps.get(skuId.toString()).toString();
            return JSON.parseObject(cartJson, Cart.class);
        }
        throw new CartException("您的购物车中没有该商品记录！");
    }

    private String getUserId() {
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        if (userInfo.getUserId() != null) {
            // 如果用户的id不为空，说明该用户已登录，添加购物车使用userId作为key
            return userInfo.getUserId().toString();
        }
        // 否则，说明该用户为登录，以userKey作为key
        return userInfo.getUserKey();
    }

    @Async
    public ListenableFuture<Object> executor1() {
        try {
            System.out.println("executor1方法开始执行");
            TimeUnit.SECONDS.sleep(4);
            System.out.println("executor1方法结束执行");
            return AsyncResult.forValue("executor1"); // 正常响应
        } catch (Exception e) {
            e.printStackTrace();
            return AsyncResult.forExecutionException(e); // 异常响应
        }
    }

    @Async
    public String executor2() {
        try {
            System.out.println("executor2方法开始执行");
            TimeUnit.SECONDS.sleep(5);
            System.out.println("executor2方法结束执行");
            //int i = 1/0; // 制造异常
            return "executor2"; // 正常响应
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public List<Cart> queryCarts() {

        //1.以userKey查询未登录的购物车
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        String userKey = userInfo.getUserKey();

        String unloginKey = KEY_PREFIX + userKey;
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(unloginKey);
        // 获取未登录购物车的json集合
        List<Object> cartJsons = hashOps.values();
        List<Cart> unLoginCarts = null;
        if (!CollectionUtils.isEmpty(cartJsons)){
            unLoginCarts = cartJsons.stream().map(cartJson -> {
                Cart cart = JSON.parseObject(cartJson.toString(), Cart.class);
                // 查询实时价格
                String currentPriceString = this.redisTemplate.opsForValue().get(PRICE_PREFIX + cart.getSkuId());
                cart.setCurrentPrice(new BigDecimal(currentPriceString));
                return cart;
            }).collect(Collectors.toList());
        }

        //2.获取登录状态：拦截器 threadLocal 获取userId 如果userId为空，说明没有登录，直接返回未登录的购物车
        Long userId = userInfo.getUserId();
        if (userId == null){
            return unLoginCarts;
        }

        //3.如果登陆了，则合并未登录的购物车到已登录的购物车中
            // 遍历未登录的购物车列表获取到skuId和登录购物车内层map集合中的key作比较，有的更新数量，没有的新增该商品
        BoundHashOperations<String, Object, Object> loginHashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        if (!CollectionUtils.isEmpty(unLoginCarts)){
            unLoginCarts.forEach(cart -> {
                String skuId = cart.getSkuId().toString();
                BigDecimal count = cart.getCount(); //未登录购物车的数量
                //判断已登录的购物车是否包含该商品，有则更新数量，如果不包含新增
                if (loginHashOps.hasKey(skuId)){
                    //获取已登录购物车对应skuId的记录
                    String cartJson = loginHashOps.get(skuId).toString();
                    cart = JSON.parseObject(cartJson, Cart.class);
                    cart.setCount(cart.getCount().add(count));
                    // 更新到redis和mysql
                    this.cartAsyncService.updateCartByUserIdAndSkuId(userId.toString(),cart);
                } else{
                    cart.setUserId(userId.toString());
                    this.cartAsyncService.saveCart(cart.getUserId(),cart);
                }
                loginHashOps.put(skuId,JSON.toJSONString(cart));
            });
            //4.删除未登录的购物车
            this.redisTemplate.delete(KEY_PREFIX + userKey);
            this.cartAsyncService.deleteCart(userKey);
        }

        //5.查询已登录的购物车，返回给用户
        List<Object> loginCartJsons = loginHashOps.values();
        if (!CollectionUtils.isEmpty(loginCartJsons)){
            return loginCartJsons.stream().map(cartJson ->{
                Cart cart = JSON.parseObject(cartJson.toString(), Cart.class);
                //设置实时价格
                String currentPriceString = this.redisTemplate.opsForValue().get(PRICE_PREFIX + cart.getSkuId());
                cart.setCurrentPrice(new BigDecimal(currentPriceString));
                return cart;
            }).collect(Collectors.toList());
        }
        return null;
    }


    public void updateNum(Cart cart) {
        // 获取登录状态
        String userId = this.getUserId();

        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        String skuId = cart.getSkuId().toString();
        BigDecimal count = cart.getCount();
        if (hashOps.hasKey(skuId)){
            String cartJson = hashOps.get(skuId).toString();
            cart = JSON.parseObject(cartJson, Cart.class);
            cart.setCount(count);

            //双写入数据库
            hashOps.put(skuId,JSON.toJSONString(cart));
            this.cartAsyncService.updateCartByUserIdAndSkuId(userId,cart);
        }
    }

    public void updateStatus(Cart cart) {
        // 获取登录状态
        String userId = this.getUserId();

        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        String skuId = cart.getSkuId().toString();
        Boolean check = cart.getCheck();
        if (hashOps.hasKey(skuId)){
            String cartJson = hashOps.get(skuId).toString();
            cart = JSON.parseObject(cartJson, Cart.class);
            cart.setCheck(check);

            //双写入数据库
            hashOps.put(skuId,JSON.toJSONString(cart));
            this.cartAsyncService.updateCartByUserIdAndSkuId(userId,cart);
        }
    }


    public void deleteCart(Long skuId) {
        String userId = this.getUserId();

        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);

        hashOps.delete(skuId.toString());
        this.cartAsyncService.deleteCartBySkuId(userId,skuId);
    }

    public List<Cart> queryCheckedCarts(Long userId) {

        String key = KEY_PREFIX + userId;
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(key);
        List<Object> cartJsons = hashOps.values();
        if (CollectionUtils.isEmpty(cartJsons)){
            return null;
        }
        return cartJsons.stream().map(cartJson->
            JSON.parseObject(cartJson.toString(),Cart.class)
        ).filter(cart -> cart.getCheck()).collect(Collectors.toList());
    }
}
